@use 'form-field-sizing';
@use '../../cdk/a11y/a11y';

// Mixin that can be included to override the default MDC text-field
// styles to fit our needs. See individual comments for context on why
// certain MDC styles need to be modified.
@mixin private-text-field-structure-overrides() {
  // Unset the border set by MDC. We move the border (which serves as the Material Design
  // text-field bottom line) into its own element. This is necessary because we want the
  // bottom-line to span across the whole form-field (including prefixes and suffixes).
  .mat-mdc-input-element {
    border: none;
  }

  // In order to ensure proper alignment of the floating label, we reset its line-height.
  // The line-height is not important as the element is absolutely positioned and only has one line
  // of text.
  .mat-mdc-form-field .mdc-floating-label {
    line-height: normal;
  }

  // Reset the height that MDC sets on native input elements. We cannot rely on their
  // fixed height as we handle vertical spacing differently. MDC sets a fixed height for
  // inputs and modifies the baseline so that the textfield matches the spec. This does
  // not work for us since we support arbitrary form field controls which don't necessarily
  // use an `input` element. We organize the vertical spacing on the infix container.
  .mdc-text-field--no-label:not(.mdc-text-field--textarea)
  .mat-mdc-input-element.mdc-text-field__input,
  .mat-mdc-text-field-wrapper .mat-mdc-input-element {
    height: auto;
  }

  // Root element of the mdc-text-field. As explained in the height overwrites above, MDC
  // sets a default height on the text-field root element. This is not desired since we
  // want the element to be able to expand as needed.
  .mat-mdc-text-field-wrapper {
    height: auto;
    flex: auto;
  }

  // The icon prefix/suffix is closer to the edge of the form-field than the infix is in a
  // form-field with no prefix/suffix. Therefore the standard padding has to be removed when showing
  // an icon prefix or suffix. We can't rely on MDC's styles for this because we use a different
  // structure for our form-field in order to support arbitrary height input elements.
  .mat-mdc-form-field-has-icon-prefix .mat-mdc-text-field-wrapper {
    padding-left: 0;
  }
  .mat-mdc-form-field-has-icon-suffix .mat-mdc-text-field-wrapper {
    padding-right: 0;
  }
  [dir='rtl'] {
    // Undo the above padding removals which only apply in LTR languages.
    .mat-mdc-text-field-wrapper {
      padding-left: form-field-sizing.$mat-form-field-end-padding;
      padding-right: form-field-sizing.$mat-form-field-end-padding;
    }
    // ...and apply the correct padding resets for RTL languages.
    .mat-mdc-form-field-has-icon-suffix .mat-mdc-text-field-wrapper {
      padding-left: 0;
    }
    .mat-mdc-form-field-has-icon-prefix .mat-mdc-text-field-wrapper {
      padding-right: 0;
    }
  }

  // The default MDC text-field implementation does not support labels which always float.
  // MDC only renders the placeholder if the input is focused. We extend this to show the
  // placeholder if the form-field label is set to always float.
  // TODO(devversion): consider getting a mixin or variables for this (currently not available).
  // Stylelint no-prefixes rule disabled because MDC text-field only uses "::placeholder" too.
  // stylelint-disable-next-line material/no-prefixes
  .mat-mdc-form-field-label-always-float .mdc-text-field__input::placeholder {
    transition-delay: 40ms;
    transition-duration: 110ms;
    opacity: 1;
  }

  // Since we moved the horizontal spacing from the input to the form-field flex container
  // and the MDC floating label tries to account for the horizontal spacing, we need to reset
  // the shifting since there is no padding the label needs to account for. Note that we do not
  // want do this for labels in the notched-outline since MDC keeps those labels relative to
  // the notched outline container, and already applies a specific horizontal spacing which
  // we do not want to overwrite. *Note*: We need to have increased specificity for this
  // override because the `right` property will be set with higher specificity in RTL mode.
  .mat-mdc-text-field-wrapper .mat-mdc-form-field-infix .mdc-floating-label {
    left: auto;
    right: auto;
  }

  // MDC sets the input elements in outline appearance to "display: flex". There seems to
  // be no particular reason why this is needed. We set it to "inline-block", as it otherwise
  // could shift the baseline.
  .mat-mdc-text-field-wrapper.mdc-text-field--outlined .mdc-text-field__input {
    display: inline-block;
  }

  // As mentioned in the override before, MDC aligns the label using percentage. This means that
  // MDC tries to offset the label when the parent element changes in the notched-outline. For
  // example, the outline stroke width changes on focus. Since we updated the label to use a fixed
  // position, we don't need the vertical offsetting (that will shift the label incorrectly now).
  // Note: Increased specificity needed here since MDC overwrites the padding on `:focus`.
  .mat-mdc-form-field .mat-mdc-text-field-wrapper.mdc-text-field .mdc-notched-outline__notch {
    padding-top: 0;
  }

  // Unset the baseline adjustment styles that are applied to the `.mdc-text-field` before
  // pseudo element. We control the vertical alignment of form field controls using infix
  // spacing since we support custom form-field controls. Those don't necessarily have an
  // explicit height that matches with the Material Design specification. If the height isn't
  // explicitly set to a specific value by MDC, the control will not align correctly vertically.
  // e.g. No vertical spacing to the bottom-line if the control is too large.
  .mat-mdc-text-field-wrapper::before {
    content: none;
  }

  // The outline of the `fill` appearance is achieved through a background color
  // which won't be visible in high contrast mode. Add an outline to replace it.
  .mat-form-field-appearance-fill .mat-mdc-text-field-wrapper {
    @include a11y.high-contrast(active, off) {
      outline: solid 1px;
    }
  }
}
